package com.spring.security.filter;

import com.spring.security.utils.TokenInfo;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 授权
 */
@Component
@Order(2)
public class AuthorizationFilter implements GlobalFilter, InitializingBean {

    private Set<String> skipUrls = new HashSet<>();


    @Override
    public void afterPropertiesSet() throws Exception {
        skipUrls.add("/oauth/token");
        skipUrls.add("/oauth/check_token");
        skipUrls.add("/user/getUser");
        skipUrls.add("/auth/getAuth");
    }


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestPath = exchange.getRequest().getURI().getPath();
        if (isSkip(requestPath)) {
            return chain.filter(exchange);
        }
        TokenInfo info = exchange.getAttribute("tokenInfo");
        if (info == null) {
            throw new RuntimeException("token信息为空");
        }
        if (!info.isActive()) {
            throw new RuntimeException("token过期");
        }
        hasPremission(info, requestPath);
        return chain.filter(exchange);
    }

    private void hasPremission(TokenInfo info, String requestPath) {
        if (Arrays.asList(info.getAuthorities()).
                stream().filter(requestPath::equals).
                collect(Collectors.toSet()).isEmpty()) {
            throw new RuntimeException("没有权限访问");
        }
    }

    private boolean isSkip(String requestPath) {
        for (String skipUrl : skipUrls) {
            if (requestPath.contains(skipUrl)) {
                return true;
            }
        }
        return false;
    }
}
